package ru.sstu.renju.swing;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.Serializable;
import java.util.Observable;
import java.util.Observer;
import java.util.ResourceBundle;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

import ru.sstu.renju.config.Config;
import ru.sstu.renju.core.Game;
import ru.sstu.renju.core.GameResult;
import ru.sstu.renju.core.Move;
import ru.sstu.renju.core.Player;
import ru.sstu.renju.players.HumanPlayer;
import ru.sstu.renju.swing.renderers.SwingRenderer;

/**
 * {@link GamePanel} class represents main game panel.
 *
 * @author denis_murashev
 * @since Renju 1.0
 */
public class GamePanel extends JPanel implements Observer {

	private static final long serialVersionUID = -3552521129085920198L;

	private final Config config;

	private Game game;

	private SwingRenderer renderer;

	private HumanListener mouseListener;

	/**
	 * Initializes panel.
	 *
	 * @param config configuration
	 */
	public GamePanel(Config config) {
		this.config = config;
		renderer = (SwingRenderer) config.getRenderer();
		int size = config.getGameSize() * config.getCellSize();
		setPreferredSize(new Dimension(size, size));
		for (Player player : config.getPlayers()) {
			if (player instanceof HumanPlayer) {
				mouseListener = new HumanListener((HumanPlayer) player);
				addMouseListener(mouseListener);
			}
		}
	}

	/**
	 * @param game the game to set
	 */
	public void setGame(Game game) {
		if (this.game != null) {
			this.game.stop();
			this.game.deleteObservers();
			mouseListener.flush();
		}
		this.game = game;
		this.game.addObserver(this);
	}

	/**
	 * @param renderer the renderer to set
	 */
	public void setRenderer(SwingRenderer renderer) {
		this.renderer = renderer;
		repaint();
	}

	@Override
	public void update(Observable o, Object arg) {
		repaint();
		if (game.getResult().getWinner() != null) {
			ResourceBundle bundle = config.getBundle();
			JOptionPane.showMessageDialog(this,
					bundle.getString(game.getResult().getWinner().getText()),
					bundle.getString("app.title"),
					JOptionPane.INFORMATION_MESSAGE);
		}
	}

	@Override
	protected void paintComponent(Graphics g) {
		renderer.paintField(g);
		if (game != null) {
			for (int i = 0; i < config.getGameSize(); i++) {
				for (int j = 0; j < config.getGameSize(); j++) {
					renderer.paintCell(g, i, j, game.getCell(i, j));
				}
			}
			GameResult result = game.getResult();
			if (result != null && result.getWinnigRow() != null) {
				renderer.paintRow(g, result.getWinnigRow());
			}
		}
	}

	private final class HumanListener extends MouseAdapter
			implements Serializable {

		private static final long serialVersionUID = -4390155311397287144L;

		private final HumanPlayer player;

		/**
		 * @param player player
		 */
		private HumanListener(HumanPlayer player) {
			this.player = player;
		}

		@Override
		public void mouseClicked(MouseEvent e) {
			if (game != null) {
				int x = e.getX() / config.getCellSize();
				int y = e.getY() / config.getCellSize();
				player.setMove(new Move(game, x, y));
			}
		}

		private void flush() {
			player.setMove(null);
		}
	}
}
